package edu.unika.aifb.graphindex.query;

/**
 * Copyright (C) 2009 G�nter Ladwig (gla at aifb.uni-karlsruhe.de)
 * 
 * This file is part of the graphindex project.
 *
 * graphindex is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License, version 2
 * as published by the Free Software Foundation.
 * 
 * graphindex is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with graphindex.  If not, see <http://www.gnu.org/licenses/>.
 */

import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;

import javax.print.attribute.standard.MediaSize.Other;

import org.jgrapht.graph.DirectedMultigraph;

import edu.unika.aifb.graphindex.searcher.keyword.model.KeywordElement;

public class QueryGraph extends DirectedMultigraph<QNode,QueryEdge> implements Serializable {
	private static final long serialVersionUID = -1356274835706353638L;
	private Set<String> nodeLabels;
	private Set<String> edges;
	private Set<QNode> keywordNodes;
	
	public QueryGraph() {
		super(QueryEdge.class);
	}

	public QueryEdge addEdge(String src, String property, String trg) {
		return addEdge(new QNode(src), property, new QNode(trg));
	}
	
	public QueryEdge addEdge(QNode src, String property, QNode trg) {
		if (!containsVertex(src))
			addVertex(src);
		else
			src = getNodeByLabel(src.getLabel());
		
		if (!containsVertex(trg))
			addVertex(trg);
		else
			trg = getNodeByLabel(trg.getLabel());
		
		QueryEdge e = new QueryEdge(src, trg, property, this);
		addEdge(src, trg, e);
		return e;
	}
	
	public QNode getNodeByLabel(String label) {
		for (QNode node : vertexSet())
			if (node.getLabel().equals(label))
				return node;
		return null;
	}
	
	public int edgeCount() {
		return edgeSet().size();
	}
	
	public int nodeCount() {
		return vertexSet().size();
	}
	
	public int degreeOf(QNode node) {
		return inDegreeOf(node) + outDegreeOf(node);
	}
	
	public Set<String> getNodeLabels(){
		if(nodeLabels == null){
			nodeLabels = new HashSet<String>();
			for (QNode node : this.vertexSet()) {
				nodeLabels.add(node.getLabel());
			}
		}
		return nodeLabels;
	}
	
	public Set<QNode> getKeywordNodes(){
		if(keywordNodes == null){
			keywordNodes = new HashSet<QNode>();
			for (QNode node : this.vertexSet()) {
				if(node.isKeywordNode())
					keywordNodes.add(node);
			}
		}
		return keywordNodes;
	}
	
	public Set<String> getEdgeLabels(){
		if(edges == null){
			edges = new HashSet<String>();
			for (QueryEdge edge : this.edgeSet()) {
				edges.add(edge.getLabel());
			}
		}
		return edges;
	}
	
	public Set<QNode> predecessors(QNode node) {
		Set<QNode> preds = new HashSet<QNode>();
		for (QueryEdge e : incomingEdgesOf(node))
			preds.add(e.getSource());
		return preds;
	}

	public Set<QNode> successors(QNode node) {
		Set<QNode> succs = new HashSet<QNode>();
		for (QueryEdge e : outgoingEdgesOf(node))
			succs.add(e.getTarget());
		return succs;
	}
	
	public Set<KeywordElement> getKeywordElements(){
		Set<KeywordElement> keywordElements = new HashSet<KeywordElement>();
		for(QNode node : vertexSet())
			if(node.isKeywordNode())
				keywordElements.add(node.getKeywordElement());
		return keywordElements;
	}
	
	public QueryGraph deepCopy() {
		QueryGraph graph = new QueryGraph();
		
		for (QueryEdge e : edgeSet()) {
			graph.addEdge((QNode)e.getSource().clone(), e.getLabel(), (QNode)e.getTarget().clone());
		}
		
		return graph;
	}
	
	public boolean isValid(){
		for(QNode keywordNode : getKeywordNodes()){
			if(keywordNode.getKeywordElement().entities.size() > 0){
				for(QNode successorNode : this.successors(keywordNode)){
					if(successorNode.getLabel().startsWith("db"))
						return false;
				}
			}
		}
		
//		if(edgeSet().size() > (vertexSet().size() - 1))
//			return false;
		
		return true;
	}
	
	public boolean isIsomorphTo(QueryGraph queryGraph){
		if(this.vertexSet().size() == 1 && queryGraph.vertexSet().size() == 1){
			return vertexSet().iterator().next().getKeywordElement().getElementType().equalsIgnoreCase(queryGraph.vertexSet().iterator().next().getKeywordElement().getElementType());
		}
		
		if(this.vertexSet().size() != queryGraph.vertexSet().size())
			return false;
		if(this.getEdgeLabels().containsAll(queryGraph.getEdgeLabels()) && queryGraph.getEdgeLabels().containsAll(this.getEdgeLabels())){
			if(this.edgeCount() == queryGraph.edgeCount())
				return true;
		}
		return false;
	}
}
